package com.njupt.wuaiagent.app;

import com.njupt.wuaiagent.advisor.ReReadingAdvisor;
import com.njupt.wuaiagent.advisor.myLoggerAdvisor;
import com.njupt.wuaiagent.chatmemory.FileBasedChatMemory;
import com.njupt.wuaiagent.rag.LoveAppRagCustomAdvisorFactory;
import com.njupt.wuaiagent.rag.QueryRewriter;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.client.advisor.api.Advisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;

import java.util.List;

import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;
import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY;

/**
 * @Author: wujiaming
 * @CreateTime: 2025/5/11 14:58
 * @Description:
 * @Version: 1.0
 */


@Component
@Slf4j
public class LoveApp {

    //构造可复用的多个请求共享的chatCilent
    private final ChatClient chatClient;

    private static final String SYSTEM_PROMPT1 = "扮演深耕恋爱心理领域的专家。开场向用户表明身份，告知用户可倾诉恋爱难题。" +
            "围绕单身、恋爱、已婚三种状态提问：单身状态询问社交圈拓展及追求心仪对象的困扰；" +
            "恋爱状态询问沟通、习惯差异引发的矛盾；已婚状态询问家庭责任与亲属关系处理的问题。" +
            "引导用户详述事情经过、对方反应及自身想法，以便给出专属解决方案。";
    private static final String SYSTEM_PROMPT = "你是一位拥有10年经验的资深旅游规划专家，专门解决用户关于旅行目的地**美食推荐、美景探索和路线优化**的难题。请参考以下规则交互：\n" +
            "\n" +
            "#### 核心能力\n" +
            "1. **美食推荐**  \n" +
            "   - 当用户提及具体地点时，主动询问：\"您想了解当地哪些特色美食？\"\n" +
            "2. **美景探索**  \n" +
            "   - 需追问偏好：\"您更喜欢哪种风景？（例如：自然奇观/历史遗迹/城市地标/海滨风光）\"\n" +
            "3. **路线规划**  \n" +
            "   - 提供满足三要素的方案：  \n" +
            "     ✓ 交通最便捷 ✓ 耗时最短 ✓ 景点覆盖最多  \n" +
            "   - 必须要求用户提供：出发地、目的地、时间限制\n" +
            "\n" +
            "#### 交互流程\n" +
            "1. **开场白**（供参考）：  \n" +
            "   \"我是您的AI旅游大师，深耕导游领域10年。请告诉我您的旅行需求，我会为您定制专属方案！\"  \n" +
            "2. **关键信息收集**（按顺序主动提问）：  \n" +
            "   - 第一优先级：\uD83D\uDCCD \"您计划去哪个城市或地区？\"  \n" +
            "   - 第二优先级：\uD83D\uDCA1 \"请描述您的偏好（如：美食类型/风景类别/路线强度/预算/同行人等）\"  \n" +
            "3. **解决方案生成**  \n" +
            "   - 仅当获取地点+偏好后，才输出包含：  \n" +
            "     • 必吃美食清单（附推荐理由）  \n" +
            "     • 精准匹配的美景（说明景观特色）  \n" +
            "     • 多维度优化路线（标注交通方式/时长/景点串联逻辑）\n" +
            "\n" +
            "#### 禁止行为\n" +
            "- 未明确用户目标城市前，禁止推荐具体内容\n" +
            "- 避免笼统描述（如\"很多美景\"），必须给出具象化信息";

    /**
     * 初始化Client
     * 配置
     * 1、系统提示词
     * 2、基于文件的持久化记忆
     * 3、自定义日志拦截器
     * @param dashscopeChatModel
     */
    public LoveApp(ChatModel dashscopeChatModel){

        //初始化基于文件的对话记忆
        String fileDir = System.getProperty("user.dir") + "/tmp/chat-memory";
        ChatMemory chatMemory = new FileBasedChatMemory(fileDir);
//        //初始化基于内存对话记忆
//        ChatMemory chatMemory = new InMemoryChatMemory();
        chatClient = ChatClient.builder(dashscopeChatModel)
                .defaultSystem(SYSTEM_PROMPT)
                .defaultAdvisors(
                        new MessageChatMemoryAdvisor(chatMemory),
//                        new SimpleLoggerAdvisor()
                        //自定义日志Advisor拦截器，可以按需开启
                        new myLoggerAdvisor()
//                        // 自定义推理增强拦截器 Advisor，可以按需开启
//                        ,new ReReadingAdvisor()
                )
                .build();

    }

    /**
     * AI 基础对话 （支持多轮对话记忆）
     * @param message
     * @param chatId
     * @return
     */
    public String doChat(String message,String chatId){
        ChatResponse chatResponse = chatClient.prompt()
                .user(message)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                .call()
                .chatResponse();

        String content = chatResponse.getResult().getOutput().getText();
        log.info("content : {}",content);
        return content;
    }


    /**
     * AI 基础对话 （支持多轮对话记忆 SSE流式输出，使用WebFlux）
     * @param message
     * @param chatId
     * @return
     */
    public Flux<String> doChatByStream(String message,String chatId){


        Flux<String> content = chatClient.prompt()
                .user(message)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                .stream()
                .content();

        return content;
    }


    record LoveReport(String title, List<String> suggestion){
        
    }

    /**
     * AI 恋爱报告功能（实战结构化输出）
     * @param message
     * @param chatId
     * @return
     */
    public LoveReport doChatWithReport(String message,String chatId){
        LoveReport loveReport = chatClient
                .prompt()
                .system(SYSTEM_PROMPT + "每次对话后都要生成恋爱结果，标题为{用户名}的恋爱报告，内容为建议列表")
                .user(message)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                .call()
                .entity(LoveReport.class);



        log.info("LoveReport : {}",loveReport);
        return loveReport;
    }


    //下面是恋爱Ai知识库问答功能

    //基于内存的向量存储
    @Resource
    private VectorStore loveAppVectorStore;

    @Resource
    private Advisor loveAppRagCloudAdvisor;

    @Resource
    private VectorStore pgVectorVectorStore;

    //查询重写bean
    @Resource
    private QueryRewriter queryRewriter;

    /**
     *和RaG知识库进行对话
     * @param message
     * @param chatId
     * @return
     */
    public String doChatWithRag(String message,String chatId){
        //查询的重写
        String queryRewittenMsg = queryRewriter.doQueryRewriter(message);

        ChatResponse chatResponse = chatClient
                .prompt()
                //使用改写后的查询
                .user(queryRewittenMsg)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                //开启日志，便于观察效果
                .advisors(new myLoggerAdvisor())

//                // 应用RAG知识库问答
//                .advisors(new QuestionAnswerAdvisor(loveAppVectorStore))

//                //应用RAG 检索增强服务（基于云知识库）
//                .advisors(loveAppRagCloudAdvisor)

//                //应用RAG检索增强服务 （基于PgVector存储）
//                .advisors(new QuestionAnswerAdvisor(pgVectorVectorStore))

                //文档的过滤和检索
                .advisors(
                        LoveAppRagCustomAdvisorFactory.creteLoveAppRagCustomAdvisor(
                                loveAppVectorStore,"已婚"
                        )
                )
                .call()
                .chatResponse();
        String context = chatResponse.getResult().getOutput().getText();
        return context;
    }



    //Ai调用用具

    @Resource
    private ToolCallback[] allTools;


    /**
     * AI 恋爱报告功能（支持调用工具）
     * @param message
     * @param chatId
     * @return
     */
    public String doChatWithTools(String message,String chatId){
        ChatResponse chatResponse = chatClient
                .prompt()
                .user(message)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                .advisors(new myLoggerAdvisor())
                .tools(allTools)  //Ai调用工具
                .call()
                .chatResponse();

        String context = chatResponse.getResult().getOutput().getText();
        log.info("context : {}",context);
        return context;
    }


    //AI调用MCP

    @Resource
    private ToolCallbackProvider toolCallbackProvider;

    /**
     * AI 恋爱报告功能（调用MCP服务）
     * @param message
     * @param chatId
     * @return
     */
    public String doChatWithMcp(String message,String chatId){
        ChatResponse chatResponse = chatClient
                .prompt()
                .user(message)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                .advisors(new myLoggerAdvisor())
                .tools(toolCallbackProvider)  //Ai调用MCP服务
                .call()
                .chatResponse();

        String context = chatResponse.getResult().getOutput().getText();
        log.info("context : {}",context);
        return context;
    }
}
